﻿using System.Xml;
using System.Xml.Linq;
using Acando.Dynamics.CRM.Silverlight.Library.CrmSdk;
using Acando.Dynamics.CRM.Silverlight.Library.MetaSdk;
using Acando.Dynamics.CRM.Silverlight.Library.Types;
using System.Collections.Generic;
using System.Linq;
using System;
using Acando.Dynamics.CRM.Silverlight.Library.Helper;
using Acando.Dynamics.CRM.Silverlight.Library.Interfaces;

namespace RiaCrm.DataAccessLayer
{
    public class RetrieveFromXmlHelper
    {
        private EntityMetadata _entityMetadata = null;
        private String _formXmlAsStr = null;
        private String _entityname = null;
        private String _organame;
        private static Dictionary<string, Pair<EntityMetadata, string>> cache = new Dictionary<string, Pair<EntityMetadata, string>>();
        //private object userstate = null;

        //public delegate void RetrieveFromXmlHelperHandler(Pair<EntityMetadata, string> result, object para);
        public delegate void RetrieveFromXmlHelperHandler(Pair<EntityMetadata, string> result);

        public event RetrieveFromXmlHelperHandler RetrieveFromXmlCompleted;

        public RetrieveFromXmlHelper(String organame)
        {
            this._organame = organame;
        }

        public void RetrieveFormXmlAsyn(string entityname, IMetaDataLayer metadatalayer,  Action<Pair<EntityMetadata, string>> callback)
        {
            this._entityname = entityname;

            this.RetrieveFromXmlCompleted += c => callback(c);

            lock (typeof(RetrieveFromXmlHelper))
            {
                if (!cache.ContainsKey(entityname))
                {
                    if (!IsolatedStoreHelper.FileExists("FormXml", entityname))
                    {

                        ExportXmlRequest formReq = new ExportXmlRequest();

                        formReq.ParameterXml = @"<importexportxml>
                                                <entities>
                                                   <entity>" + entityname + @"</entity>
                                                </entities>
                                                <nodes/>
                                                <securityroles/>    
                                                <settings/>
                                                <workflows/>
                                             </importexportxml>";

                        // Request FormXml of entity:
                        CrmServiceSoapClient crmService = SoapClientFactory.CreateCrmInstanceSilver();
                        crmService.ExecuteCompleted += new EventHandler<Acando.Dynamics.CRM.Silverlight.Library.CrmSdk.ExecuteCompletedEventArgs>(crmService_ExportXmlRequestCompleted);
                        WrapperServiceCall.ExecuteWrapper(crmService, formReq, this._organame);

                    }
                    else // Data exists in store
                    {
                        this._formXmlAsStr = IsolatedStoreHelper.GetDataFromStore("FormXml", entityname);

                        if (String.IsNullOrEmpty(this._formXmlAsStr))
                            throw new Exception("Error during loading of data from IsolatedStore");
                    }

                    // Request metaData of entity:
                    //MetadataCache metaDataCache = new MetadataCache();

                    //metaDataCache.MetadataLoaded += new MetadataCache.MetadataLoadedHandler(metaDataCach_MetadataLoaded);
                    //metaDataCache.LoadMetadata(entityname);
                    metadatalayer.LoadMetaData(entityname, loadmetadataCallback);

                }
                else // Data exist in cache
                { 
                    //var response = new Pair<EntityMetadata, string>(){ Type1=cache[entityname], Type2=entityname };
                    callback(cache[entityname]); 
                }
            }
        }
        
        void loadmetadataCallback(EntityMetadata metadata)
        {
            this._entityMetadata = metadata;

            if (!String.IsNullOrEmpty(this._formXmlAsStr))
                this.OnRetrieveFromXmlHelperCompleted(this.bothCompleted());
        }

        private void crmService_ExportXmlRequestCompleted(object sender, Acando.Dynamics.CRM.Silverlight.Library.CrmSdk.ExecuteCompletedEventArgs e)
        {
            ExportXmlResponse response = (ExportXmlResponse)e.Result;


            XElement root = XElement.Parse(response.ExportXml);

            var xmlQuery = from entities in root.Elements().Where(c => c.Name == "Entities")
                           from entity in entities.Elements()
                           from formXml in entity.Elements()
                           from forms in formXml.Elements()
                           from entity2 in forms.Elements()
                           from form in entity2.Elements().Where(c => c.Attribute("type") != null)
                           where form.Attribute("type").Value == "main"
                           select form;

            this._formXmlAsStr = xmlQuery.First().ToString();


            // Save result in IsolationStore:
            IsolatedStoreHelper.StoreData("FormXml", this._entityname, _formXmlAsStr);


            if (this._entityMetadata != null)
                this.OnRetrieveFromXmlHelperCompleted(this.bothCompleted());
        }

        void metaservice_ExecuteCompleted(object sender, Acando.Dynamics.CRM.Silverlight.Library.MetaSdk.ExecuteCompletedEventArgs e)
        {
            RetrieveEntityResponse entityResponse = (RetrieveEntityResponse)e.Result;
            this._entityMetadata = entityResponse.EntityMetadata;

            if (this._formXmlAsStr != null)
                this.OnRetrieveFromXmlHelperCompleted(this.bothCompleted());
        }

        private Pair<EntityMetadata, string> bothCompleted()
        {
            if (!cache.ContainsKey(this._entityMetadata.LogicalName))
            {
                cache.Add(this._entityMetadata.LogicalName, new Pair<EntityMetadata, string>()
                                                                {
                                                                    Type1 = this._entityMetadata,
                                                                    Type2 = this._formXmlAsStr
                                                                }
                            );
            }

           
            //cache.Add(this._entityMetadata.LogicalName, new Pair<EntityMetadata, string>()
            //{
            //    Type1 = this._entityMetadata,
            //    Type2 = this._formXmlAsStr
            //}
            //            );
            


            return cache[this._entityMetadata.LogicalName];
        }


        protected virtual void OnRetrieveFromXmlHelperCompleted(Pair<EntityMetadata, string> e)
        {
            if (RetrieveFromXmlCompleted != null)
                RetrieveFromXmlCompleted(e);

        }
    }
}
